[Coding024] Sort - 归并排序

归并排序

Ben 2024/01/09

More coding records

Get the knowledge flowing and circulating! :)

目录

标题:归并排序

归并排序(英语:Merge sort,或mergesort),是建立在归并操作上的一种有效的排序算法,效率为O(nlogn)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。

img

Fig. 使用合并排序为一列数字进行排序的过程

概述

采用分治法:

  • 分割:递归地把当前序列平均分割成两半;

  • 集成:在保持元素顺序的同时将上一步得到的子序列集成到一起(归并)。

归并操作

归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。

递归法(Top-down)
  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置

  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

  4. 重复步骤3直到某一指针到达序列尾

  5. 将另一序列剩下的所有元素直接复制到合并序列尾


迭代法(Bottom-up)

原理如下(假设序列共有 n 个元素):

  1. 将序列每相邻两个数字进行归并操作,形成 ceil(n/2) 个序列,排序后每个序列包含两/一个元素

  2. 若此时序列数不是1个则将上述序列再次归并,形成ceil(n/4)个序列,每个序列包含四/三个元素

  3. 重复步骤2,直到所有元素排序完毕,即序列数为1

——维基百科

归并排序动画演示

undefined

ms_1_Animation

ms_2_Animation

Java语言代码实现(版本1)

经典方法 - 两个函数

运行结果

样例1:

image-20240108194748979

样例2:

image-20240109114154986

针对样例2的手绘图

image-20240109124347757

Fig. 各函数调用关系示意图

image-20240109122756655

Java语言代码实现(版本2)

一个函数搞定(MergeSort,内置递归)

运行结果

image-20240108194415387

 

复杂度

平均时间复杂度Θ(nlogn)
最坏时间复杂度Θ(nlogn)
最优时间复杂度Θ(nlogn)
空间复杂度Θ(n)
最佳解有时是

复杂度分析

image-20240108200414690

归并排序树的高度 hO(logn)

  • 每一次调用的时候我们都把序列分为两部分;

深度为 i 的那层的节点总数是 n

  • 我们切分与合并了 2i 个长度为 n/2i 的序列;

  • 我们进行了2i+1次递归调用;

所以,归并排序的整体运行时间为 O(nlogn)

 

稳定性

归并排序是否稳定排序取决于比较条件中,左边的元素和右边的元素比较情况:

  • 如果是左边元素 <= 右边元素

    • new = 左边元素(小于等于的时候,都是先取左边元素)【稳定】

  • else

    • new = 右边元素


  • 如果是左边元素 < 右边元素

    • new = 左边元素(小于的时候,先取左边元素)

  • else

    • new = 右边元素(大于等于的时候,取右边元素)【不稳定】